﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

// Reviewed

#pragma once
#include "ICurveOperate.h"
#include "GeometryErrorCode.h"


namespace gcmp
{

    /// \brief 曲线操作类，用于实现曲线的修改和逻辑处理
    ///
    class GCMP_GEOMETRY_INTERFACE_EXPORT AlgorithmCurveOperate
    {
    public:
        /// \brief  从二维曲线集合中搜索多边形
        /// \param pCurve2ds    二维曲线集合
        /// \param opPolygons   多边形的集合
        /// \param polygonLoopCoedgeIndexToOriginCurveIndexMap  polygonList中某一曲线所在的polygon序号，
        ///                                                       Loop序号和Coedge序号与它在原始曲线集合(pCurve2ds)中序号的对应关系
        /// \param  distanceEpsilon 距离误差
        /// \param  errorCurves     搜索完多边形后剩余的曲线
        /// \return  多边形中环的状态
        static EnLoopsState Curve2dlistToPolygonLists(
            const std::vector<const ICurve2d*>& pCurve2ds,
            std::vector<OwnerPtr<IPolygon>>& opPolygons,
            std::map<std::tuple<int, int, int>, int>& polygonLoopCoedgeIndexToOriginCurveIndexMap,
            double distanceEpsilon,
            std::vector<const ICurve2d*>& errorCurves
        );

        
        /// \brief   体裁线
        /// \param  pCurve                 三维曲线
        /// \param  pBody                  体
        /// \param  bOnReserved            是否保留在体上的曲线部分
        /// \param  opResultCurves         扣减得到的三维曲线集合
        /// \return  成功返回true，失败返回false
        static bool BodySubtractCurve3d(
            const ICurve3d* pCurve,
            const IBody* pBody, 
            bool bOnReserved, 
            std::vector<OwnerPtr<ICurve3d>>& opResultCurves
        );

        /// \brief      三维曲线交封闭体得到三维曲线集合
        /// \param  const ICurve3d* pCurve        三维曲线
        /// \param  const IBody* pBody            封闭的体
        /// \param  bool bOnReserved              是否保留在体上的曲线部分
        /// \param  resultCurves                  相交得到的三维曲线集合
        static bool BodyIntersectCurve3d(const ICurve3d* pCurve, const IBody* pBody, bool bOnReserved, std::vector<OwnerPtr<ICurve3d>>& resultCurves);


        
        /// \brief    曲线在指定参数分割
        /// \param pOriginalCurve  原始曲线
        /// \param param             指定参数,参数必须在曲线参数域范围内
        /// \param opCurveLeft     参数域范围为[min,param]的曲线
        /// \param opCurveRight    参数域范围为[param，max]的曲线
        /// \return  成功返回true，失败返回false
        static bool SubdivideCurve3d(
            const ICurve3d* pOriginalCurve, 
            double parameter, 
            OwnerPtr<ICurve3d> &opCurveLeft, 
            OwnerPtr<ICurve3d> &opCurveRight
        );

        
        /// \brief    截取指定参数范围内的曲线
        /// \param pOriginalCurve     原始曲线
        /// \param startParameter       指定起始参数,参数必须在曲线参数域范围内
        /// \param endParameter         指定结束参数,参数必须在曲线参数域范围内
        /// \param opResultCurve 参数域范围为[paramStart,paramEnd]的曲线
        /// \return    成功返回true，失败返回false
        static bool TrimCurve3d(
            const ICurve3d* pOriginalCurve,
            double startParameter, 
            double endParameter, 
            OwnerPtr<ICurve3d> &opResultCurve);

        
        /// \brief   计算曲线外一点到曲线的最近的垂点
        /// \param pCurve2d            二维曲线
        /// \param pointOutCurve       曲线外点
        /// \param perpendicularPoint  垂点（多个时取离点曲线外点最近的垂点）
        /// \param  distanceEpsilon    距离精度
        /// \return  成功返回true，失败返回false
        static bool GetPerpendicularPoint(
            const ICurve2d* pCurve2d,
            const Vector2d &pointOutCurve,
            Vector2d &perpendicularPoint, 
            double distanceEpsilon
        );


        /// \brief  曲线按首尾连接的方式排序，包括封闭情况
        /// \param[in] unsortedCurves  未排序的曲线组
        /// \param[out] sortedCurves  排序的曲线组
        /// \param[out] sortedIndexes  排序的序号
        /// \return true: 成功; false: 1)三分叉; 2) 输入曲线存在首尾未连接的情形
        static bool CreateSequencedCurves(const std::vector<const ICurve3d*>& unsortedCurves,
            std::vector<OwnerPtr<ICurve3d>>& sortedCurves,
            std::vector<int>& sortedIndexes);

        /// \brief  给定一组二维曲线，搜索多段线
        ///
        /// 不考虑自交；超过2条线共点，与其共点的所有线都以单条PolyCurve线输出; 两条线端点共点，但不是首尾相连，会将其中一条线反向
        ///
        /// \param[in] pCurve2dList        二维曲线数组
        /// \param[in] dDistanceEpsilon    距离容差
        /// \param[out] opPolyCurves       搜到的多段线集合，一个IPolyCurve是一组首尾相连的线，可以是闭合的，也可以不是闭合的。
        /// \param[out] originalCurveIndices 搜到的多段线对应的原始线（pCurve2dList ）索引集合，可以为空， 不为空时，集合size和opPolyCurves的size大小一样。
        /// \return 成功返回true，失败返回false
        static bool SearchPolyCurves(const std::vector<const ICurve2d*> &pCurve2dList, double dDistanceEpsilon, std::vector<OwnerPtr<IPolyCurve>>& opPolyCurves, std::vector<std::vector<int>>* originalCurveIndices = nullptr);
        
        /// \brief 输入一条多段线和一个多段线数组，查找多段线数组中与这条多段线全等的多段线
        ///
        /// \param[in] pPolygonCurve 输入的一条多段线
        /// \param[in] polyCurveArray 输入的多段线数组
        /// \param[out] 与输入多段线全等的多段线的索引和对应的变换矩阵
        /// \param[out] errorIndexArray 非法 PolyCurve 的索引
        /// \param[in] dDistanceEpsilon    距离容差
        /// \return 无非法情况，返回true。其他情况返回false，输出的全等多段线信息可用
        static bool SearchCongruentPolyCurves(const IPolyCurve* pPolygonCurve, const std::vector<const IPolyCurve*>& polyCurveArray, std::vector<std::pair<int, Matrix4d>>& indexAndMatrix4d, std::vector<int>* errorIndexArray = nullptr, double dDistanceEpsilon = Constants::LENGTH_EPS);

        /// \brief 输入一组多段线，将其中全等的多段线分类
        ///
        /// \param[in] polyCurveArray 输入的一组多段线
        /// \param[out] 分类的结果。输出结果是一个数组，数组中每个元素都代表一种全等多段线。
        /// 每个元素的第一个参数是这种全等多段线在输入的多段线数组中第一次出现的索引。
        /// 每个元素的第二个参数是其他全等多段线的索引和变换矩阵。
        /// \param[out] errorIndexArray 非法 PolyCurve 的索引
        /// \param[in] dDistanceEpsilon    距离容差
        /// \return 无非法情况，返回true。其他情况返回false，输出的全等多段线信息可用
        static bool ClassifyCongruentPolyCurves(const std::vector<const IPolyCurve*>& polyCurveArray, std::vector<std::pair<int, std::vector<std::pair<int, Matrix4d>>>>& classification, std::vector<int>* errorIndexArray = nullptr, double dDistanceEpsilon = Constants::LENGTH_EPS);
        
        /// \brief 输入一个目标几何数组和多个几何数组，查找与这个目标几何数组全等的几何数组，输入的几何中只支持polygon、polycurve 、curve2d
        ///
        /// 注意：几何数组中输入顺序需要类型匹配，同类型之间可以不需要保持顺序，该接口使用前请联系平台
        ///
        /// \param[in] geometries 输入的目标几何数组
        /// \param[in] geometriesArray 输入的几何数组集合
        /// \param[out] 与输入目标几何数组全等的几何数组的索引和对应的变换矩阵
        /// \param[out] errorIndexArray 输入的几何数组集合中非法的索引
        /// \param[in] dDistanceEpsilon    距离容差
        /// \return 无非法情况，返回true。其他情况返回false，输出的全等信息可用
        static bool SearchCongruentGeometrys(const std::vector<const IGeometry*>& geometries, const std::vector<std::vector<const IGeometry*>>& geometriesArray, std::vector<std::pair<int, Matrix4d>>& indexAndMatrix4d, std::vector<int>* errorIndexArray = nullptr, double dDistanceEpsilon = Constants::LENGTH_EPS);

        /// \brief 输入几何数组集合，将其中全等的几何数组分类 ，输入的几何中只支持polygon、polycurve 、curve2d
        ///
        /// 注意：几何数组中输入顺序需要类型匹配，同类型之间可以不需要保持顺序，该接口使用前请联系平台
        ///
        /// \param[in] geometriesArray 输入的几何数组集合
        /// \param[out] 分类的结果。输出结果是一个数组，数组中每个元素都代表一种全等的几何数组。
        /// 每个元素的第一个参数是这种全等几何数组在输入的几何数组集合中第一次出现的索引。
        /// 每个元素的第二个参数是其他全等几何数组集合的索引和变换矩阵。
        /// \param[out] errorIndexArray 输入的几何数组集合中非法的索引
        /// \param[in] dDistanceEpsilon    距离容差
        /// \return 无非法情况，返回true。其他情况返回false，输出的全等多段线信息可用
        static bool ClassifyCongruentGeometrys(const std::vector<std::vector<const IGeometry*>>& geometriesArray, std::vector<std::pair<int, std::vector<std::pair<int, Matrix4d>>>>& classification, std::vector<int>* errorIndexArray = nullptr, double dDistanceEpsilon = Constants::LENGTH_EPS);

        /// \brief 输入一个线框体或者单点体，计算出其与另外一个线框体的所有切线
        ///
        /// \param[in] pFirstBody 输入三维线框体或者单点体
        /// \param[in] pSecondBody 输入线框体或者单点体
        /// \param[out] opTangentLines 所有切线
        /// \param[in] distEpsilon    距离容差
        /// \return 处理结果
        static GeometryErrorCode CalculateTangentLines(const IBody* pFirstBody, const IBody* pSecondBody, std::vector<OwnerPtr<ILine3d>>& opTangentLines, double distEpsilon = Constants::LENGTH_EPS);

    };
}
